﻿// Inner Fire 游戏引擎库
// Shape - 物理形状
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 做为物理项目的形状。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-06-23

#include "collider.h"
#include <game/config/config_manager.h>
#include <game/manager/scene.h>
#include <game/object/game_object.h>

using namespace DirectX;

namespace ifire::game {
// 将常用分数转为常量
constexpr float TWO_FIFTHS = 2.0f / 5.0f;   // 球体惯量系数
constexpr float ONE_TWELFTH = 1.0f / 12.0f; // 长方体惯量系数

// 通过初始化BOX，可以使所有的项目为0
Collider::Collider(GameObject* owner)
    : game_object_(owner)
    , visual_object_(nullptr)
    , type(ShapeType::Particle)
    , half_extents(0.0f, 0.0f, 0.0f)
    , center(0.0f, 0.0f, 0.0f)
    , layer_(0), enable_(true) {}

Collider::~Collider() {}

void Collider::SetParticle() {
  type = ShapeType::Particle;
  half_extents = {0.0f, 0.0f, 0.0f};
}

void Collider::SetSphere(float radius) {
  type = ShapeType::Sphere;
  sphere.radius = radius;
}

void Collider::SetBox(IVec3 _box) {
  type = ShapeType::Box;
  half_extents = _box;
}

void Collider::SetCapsule(float radius, float start, float end) {
  type = ShapeType::Capsule;
  capsule.radius = radius;
  capsule.start = start;
  capsule.end = end;
}

void Collider::SetRadius(float radius) { sphere.radius = radius; }

void Collider::SetCenter(IVec3 value) { center = value; }

void Collider::SetCollider(ColliderInfo* info) {
  // 获得类型
  type = info->type;

  // 设置中心（通用）
  center = info->center;

  // 根据类型决定要设置的值
  switch (type) {
  case ShapeType::Sphere:
    sphere = info->sphere;
    break;
  case ShapeType::Box:
    half_extents = info->box;
    break;
  case ShapeType::Capsule:
    capsule = info->capsule;
    break;
  default:
    break;
  }
}

void Collider::SetCollider(ikit::sstr info_name) {
  auto info = ConfigManager::GetInstance().GetCollider(info_name);
  if (info) {
    SetCollider(info);
  } else {
    KERROR("Unable find collider info: %s", info_name.log_str());
  }
}

void Collider::UpdateScaledInertia(float mass, IVec3 scale) {
  // 根据形状类型计算带缩放的局部惯性张量
  switch (type) {
  case ShapeType::Sphere:
    inv_inertia = CalculateScaledSphereInertia(mass, scale);
    break;
  case ShapeType::Box:
    inv_inertia = CalculateScaledBoxInertia(mass, scale);
    break;
  case ShapeType::Capsule:
    inv_inertia = CalculateScaledCapsuleInertia(mass, scale);
    break;
  default:
    inv_inertia = ZERO_3X3;
  }
}

void Collider::UpdateWorldInertia(IVec4 rotation) {
  // 只考虑旋转，缩放已预计算
  IMat rot = XMMatrixRotationQuaternion(XMLoadFloat4(&rotation));
  auto mat = rot * XMLoadFloat3x3(&inv_inertia) * XMMatrixTranspose(rot);

  // 防止奇异矩阵
  if (fabs(XMVectorGetX(XMMatrixDeterminant(mat))) < F_EPSILON) {
    mat = XMMatrixIdentity();
  }

  XMStoreFloat3x3(&inv_inertia_world, mat);
}

IVec3 Collider::GetOffsetPosition(const IVec3& pos) const {
  auto offset = XMLoadFloat3(&pos) + XMLoadFloat3(&center);
  return StoreF3(offset);
}

IMat3 Collider::CalculateScaledSphereInertia(float mass, IVec3 scale) const {
  if (mass <= FLT_EPSILON) return ZERO_3X3;

  // 各向同性缩放（取三轴缩放均值）
  float avg_scale = (scale.x + scale.y + scale.z) / 3.0f;
  float r_eff = sphere.radius * avg_scale;

  // 明确使用分数形式 (2/5)mr²
  float I = TWO_FIFTHS * mass * r_eff * r_eff;
  float inv_I = 1.0f / I;

  return StoreM3(XMMatrixScaling(inv_I, inv_I, inv_I));
}

IMat3 Collider::CalculateScaledBoxInertia(float mass, IVec3 scale) const {
  if (mass <= FLT_EPSILON) return ZERO_3X3;

  // 1. 计算缩放后半长（box存储半长，scale是缩放系数）
  float hx = half_extents.x * fabsf(scale.x); // 取绝对值保证正值
  float hy = half_extents.y * fabsf(scale.y);
  float hz = half_extents.z * fabsf(scale.z);

  // 2. 处理退化情况（至少保证最小尺寸）
  const float minHalfExtent = 1e-6f;
  hx = imath::Max(hx, minHalfExtent);
  hy = imath::Max(hy, minHalfExtent);
  hz = imath::Max(hz, minHalfExtent);

  // 3. 计算惯性张量（对角矩阵）
  float Ixx = (mass / 12.0f) * (hy * hy + hz * hz);
  float Iyy = (mass / 12.0f) * (hx * hx + hz * hz);
  float Izz = (mass / 12.0f) * (hx * hx + hy * hy);

  // 4. 返回逆惯性矩阵（避免除零）
  return {                    //
      1.0f / Ixx, 0.0f, 0.0f, //
      0.0f, 1.0f / Iyy, 0.0f, //
      0.0f, 0.0f, 1.0f / Izz};
}

IMat3 Collider::CalculateScaledCapsuleInertia(float mass, IVec3 scale) const {
  if (mass <= FLT_EPSILON) return ZERO_3X3;

  // 1. 计算缩放后的几何参数（Y轴对齐，仅需处理Y轴缩放）
  float r_scaled =
      capsule.radius * imath::Max(scale.x, scale.z); // 半径受X/Z缩放影响
  float h_scaled =
      fabsf(capsule.end - capsule.start) * scale.y; // 高度受Y缩放影响

  // 2. 质量分配（圆柱60% + 两个半球各20%）
  const float cylinder_mass_ratio = 0.6f;
  const float hemisphere_mass_ratio = 0.2f;
  float m_cylinder = mass * cylinder_mass_ratio;
  float m_hemisphere = mass * hemisphere_mass_ratio;

  // 3. 圆柱部分惯性（Y轴为圆柱轴线）
  float I_cylinder_y = 0.5f * m_cylinder * r_scaled * r_scaled; // Iyy
  float I_cylinder_xz = m_cylinder *
                        (3.0f * r_scaled * r_scaled + h_scaled * h_scaled) /
                        12.0f; // Ixx和Izz

  // 4. 半球部分惯性（空心半球壳）
  // 4.1 半球自身惯性（绕直径）
  float I_hemisphere_self = (2.0f / 3.0f) * m_hemisphere * r_scaled * r_scaled;

  // 4.2 质心偏移距离（半球质心到圆柱端面的距离）
  float hemisphere_offset = h_scaled / 2.0f + (3.0f * r_scaled / 8.0f);

  // 4.3 平行轴定理修正（绕X/Z轴）
  float I_hemisphere_xz =
      I_hemisphere_self + m_hemisphere * hemisphere_offset * hemisphere_offset;

  // 4.4 半球绕Y轴的惯性（无需平行轴修正，因为对称）
  float I_hemisphere_y = I_hemisphere_self;

  // 5. 组合总惯性（圆柱 + 两个半球）
  float Ixx = I_cylinder_xz + 2 * I_hemisphere_xz;
  float Iyy = I_cylinder_y + 2 * I_hemisphere_y;
  float Izz = Ixx; // 对称性

  // 6. 返回逆惯性矩阵（对角线矩阵）
  return {1.0f / imath::Max(Ixx, FLT_EPSILON), 0.0f, 0.0f, 0.0f,
      1.0f / imath::Max(Iyy, FLT_EPSILON), 0.0f, 0.0f, 0.0f,
      1.0f / imath::Max(Izz, FLT_EPSILON)};
}

const DirectX::BoundingOrientedBox& Collider::GetBoundingOrientedBox(
    const RigidBody& r) const {
  if (!bounding_dirty_) return cached_bbox_;

  // 应用缩放
  XMVECTOR scaledBoxVec = XMLoadFloat3(&half_extents) * XMLoadFloat3(&r.scale_);
  XMFLOAT3 scaledBox;
  XMStoreFloat3(&scaledBox, scaledBoxVec);

  cached_bbox_ = DirectX::BoundingOrientedBox(
      GetOffsetPosition(r.position_), scaledBox, r.rotation_);
  bounding_dirty_ = false;

  return cached_bbox_;
}

const DirectX::BoundingSphere& Collider::GetBoundingSphere(
    const RigidBody& r) const {
  if (!bounding_dirty_) return cached_bsphere_;

  // 应用缩放：取最大缩放分量
  auto max_xy = imath::Max(r.scale_.x, r.scale_.y);
  float maxScale = imath::Max(max_xy, r.scale_.z);
  float scaledRadius = sphere.radius * maxScale;

  cached_bsphere_ =
      DirectX::BoundingSphere(GetOffsetPosition(r.position_), scaledRadius);
  bounding_dirty_ = false;

  return cached_bsphere_;
}

// 添加到RigidBody类中
const BoundingCapsule& Collider::GetBoundingCapsule(const RigidBody& r) const {
  if (!bounding_dirty_) return cached_bcapsule_;

  // 初始化胶囊体（当前Y轴对齐方案）
  cached_bcapsule_ = {capsule.start, capsule.end, capsule.radius};

  // 应用世界变换（不依赖具体轴向）
  auto pos = GetOffsetPosition(r.position_);
  cached_bcapsule_.Transform(
      XMLoadFloat3(&pos), XMLoadFloat4(&r.rotation_), XMLoadFloat3(&r.scale_));

  bounding_dirty_ = false;
  return cached_bcapsule_;
}

GameObject* Collider::CreateVisualObject() {
  // 系统预置的Prefab
  static ikit::sstr COLLIDER_BOX = "COLLIDER_BOX";
  static ikit::sstr COLLIDER_SPHERE = "COLLIDER_SPHERE";

  // 创建一个项目
  auto factory = Scene::GetCurrentScene()->GetObjectFactory();
  GameObject* obj = nullptr;

  // 只有Box和Sphere需要
  if (type == ShapeType::Box) {
    obj = factory->CreateSingleObject(COLLIDER_BOX);
  } else if (type == ShapeType::Sphere) {
    obj = factory->CreateSingleObject(COLLIDER_SPHERE);
  }

  SetVisualObject(obj);

  return obj;
}

void Collider::SetVisualObject(GameObject* visual_object) {
  visual_object_ = visual_object;
}

void Collider::UpdateVisualObject() {
  // 如果没有项目，则不处理
  if (!visual_object_) return;

  // 得到项目的Transform
  auto& obj_trans = game_object_->GetTransform();
  auto& trans = visual_object_->GetTransform();

  // 位置等于项目的位置加中心位置，中心位置需要根据当前的照向转为世界Position
  // 将本地偏移量转换为齐次坐标（w=1）
  auto trans_center = obj_trans.TransformDirection(center);
  auto pos = XMLoadFloat3(&obj_trans.position) + XMLoadFloat3(&trans_center);
  XMStoreFloat3(&trans.position, pos);

  // 旋转为直接继承
  trans.rotation = obj_trans.rotation;

  // 每一个Box的模型都是1:1，所以半径乘2就是缩放系数
  if (type == ShapeType::Box) {
    auto scale = XMLoadFloat3(&half_extents);
    scale *= 2.0f;
    scale *= XMLoadFloat3(&obj_trans.scale);
    XMStoreFloat3(&trans.scale, scale);
  }

  // 更新
  trans.BuildMatrix();
  visual_object_->UpdateTransform();
}

bool Collider::IsLayer(uint64_t mask) const {
  // 检查当前layer是否在mask中生效
  return (mask & (1ULL << layer_)) != 0;
}

void Collider::SetLayer(ikit::sstr name) {
  layer_ = ConfigManager::GetLayer(name);
}

void Collider::SetMask(ikit::sstr name) {
  mask_ = ConfigManager::GetMask(name);
}

size_t Collider::CheckCharaCollision() {
  // 延迟分配
  collide_results_.reserve(collide_result_limit);
  // 清空之前的结果
  collide_results_.clear();

  // 进行碰撞检查
  Scene::GetCurrentScene()->GetCharaColliderWorld()->Collide(this);

  // 返回碰撞结果
  return collide_results_.size();
}

CollideResult& Collider::GetCollisionResult(int index) {
  return collide_results_[index];
}

bool Collider::Collide(Collider* target, CollideResult& result) {
  // 根据不同类型进行处理
  if (type == ShapeType::Particle) {

  } else if (type == ShapeType::Sphere) {

  } else if (type == ShapeType::Box) {
    // 得到当前项目的Box（这个以后得缓存）
    auto& box_a = GetColliderBoundingOrientedBox();
    if (target->type == ShapeType::Box) {
      auto& box_b = target->GetColliderBoundingOrientedBox();

      if (box_a.Intersects(box_b)) {
        result.obj = target->game_object_;
        result.collider = target;
        /*KLOG("%s collider with %s", game_object_->GetName().c_str(),
            target->game_object_->GetName().c_str());*/
        return true;
      }
    }

  } else if (type == ShapeType::Capsule) {
  }

  return false;
}

void Collider::AddResult(const CollideResult& result) {
  collide_results_.push_back(result);
}

void Collider::AddToCharaColliderWorld() {
  Scene::GetCurrentScene()->GetCharaColliderWorld()->Add(this);
}

const DirectX::BoundingOrientedBox&
Collider::GetColliderBoundingOrientedBox() const {
  if (!bounding_dirty_) return cached_bbox_;

  // 得到项目的Transform
  auto& obj_trans = game_object_->GetTransform();

  // 位置等于项目的位置加中心位置，中心位置需要根据当前的照向转为世界Position
  // 将本地偏移量转换为齐次坐标（w=1）
  auto trans_center = obj_trans.TransformDirection(center);
  auto position = XMLoadFloat3(&obj_trans.position) + XMLoadFloat3(&trans_center);


  // 应用缩放
  XMVECTOR scaledBoxVec =
      XMLoadFloat3(&half_extents) * XMLoadFloat3(&obj_trans.scale);
  XMFLOAT3 scaledBox;
  XMStoreFloat3(&scaledBox, scaledBoxVec);
  
  cached_bbox_ = DirectX::BoundingOrientedBox(
      StoreF3(position), scaledBox, obj_trans.rotation);
  bounding_dirty_ = false;

  return cached_bbox_;
}

} // namespace ifire::game